/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.inspur.edp.lcm.metadata.common;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.inspur.edp.lcm.metadata.api.entity.MetadataProject;
import com.inspur.edp.lcm.metadata.api.entity.MetadataType;
import com.inspur.edp.lcm.metadata.common.configuration.GspProjectExtendHelper;
import com.inspur.edp.lcm.metadata.common.configuration.MetadataTypeConfigLoader;
import io.iec.edp.caf.common.environment.EnvironmentUtil;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.codehaus.plexus.util.StringUtils;

public class Utils {
    private static final Lock LOCK = new ReentrantLock();
    //元数据工程后缀
    private static String metadataProjSuffix;
    // pom后缀
    private static String pomSuffix;
    // 元数据包version前缀
    private static String versionPrefix;
    // 元数据包临时version后缀
    private static String versionSuffix;
    //csproj工程后缀
    private static String csprojSuffix;
    //GSP工程描述文件名称
    private static String gspProjectName;
    //元数据包后缀
    private static String metadataPackageExtension;
    //元数据包清单文件
    private static String manifestFileName;
    //原始数据修改时间文件
    private static String sourceDataFileName;
    // 强制更新依赖jar包标识文件
    private static String mavenUpdateFlagFileName;

    private static String metadataPath;
    /**
     * 获取maven工程名称。
     */
    private static String mavenProName;
    /**
     * edpParentVersion
     */
    private static String edpParentVersion;
    private static List<String> metadataPostfixTypes;

    public Utils() {
    }

    public static String getMetadataProjSuffix() {
        return ".mdproj";
    }

    public static String getPomSuffix() {
        return ".pom";
    }

    public static String getVersionPrefix() {
        return "m";
    }

    public static String getVersionSuffix() {
        return "-SNAPSHOT";
    }

    public static String getCsprojSuffix() {
        return ".csproj";
    }

    public static String getGspProjectName() {
        return "gspproject.json";
    }

    public static String getMetadataProjPath() {
        return "metadata";
    }

    public static String getMetadataPackageExtension() {
        return ".mdpkg";
    }

    public static String getManifestFileName() {
        return "manifest.json";
    }

    public static String getSourceDataFileName() {
        return "sourcedata.json";
    }

    public static String getMavenUpdateFlagFileName() {
        return "mavenupdateflag.txt";
    }

    public static String getMetadataBinPath() {
        return "bin";
    }

    public static String getApiSourceDir() {
        return "java/code/api/src";
    }

    public static String getApiTargetDir() {
        return "java/code/api/target";
    }

    public static String getCompModuleDir() {
        return "java/code/comp";
    }

    public static String getRuntimeSourceDir() {
        return "java/code/runtime/src";
    }

    public static String getSrcJavaPath() {
        return "src/main/java";
    }

    public static String getResourcesPath() {
        return "src/main/resources";
    }

    public static String getPomFile() {
        return "pom.xml";
    }

    public static String getJavaProjectPath() {
        return "java";
    }

    public static String getZipSuffix() {
        return ".zip";
    }

    public static String getJarSuffix() {
        return ".jar";
    }

    public static String getLanguageMetadataFileExtention() {
        return ".lres";
    }

    public static String getPublishPath() {
        return "publish";
    }

    public static String getJstackPath() {
        return "jstack";
    }

    public static String getCodePath() {
        return "code";
    }

    public static String getTargetPath() {
        return "target";
    }

    public static String getLibsPath() {
        return "libs";
    }

    // 获取启动jar对应的路径
    public static String getStartupPath() {
        return EnvironmentUtil.getStartupPath();
    }

    // 获取安装盘的基路径
    public static String getBasePath() {
        return EnvironmentUtil.getBasePath();
    }

    // 获取安装盘的基路径
    public static String getBasePath(boolean isDeployTool) {
        String basePath;
        if (isDeployTool) {
            basePath = FileServiceImp.combinePath(EnvironmentUtil.getStartupPath(), "../../../../");
        } else {
            basePath = EnvironmentUtil.getBasePath();
        }
        return basePath;
    }

    // 获取Server运行时路径，对应当前的jstack
    public static String getServerRTPath() {
        return EnvironmentUtil.getServerRTPath();
    }

    public static String getMavenProName() {
        if (mavenProName == null || mavenProName.isEmpty()) {
            return GspProjectExtendHelper.getInstance().getMavenProjectName();
        }
        return null;
    }

    public static String getEdpParentVersion() {
        if (mavenProName == null || mavenProName.isEmpty()) {
            return GspProjectExtendHelper.getInstance().getEdpParentVersion();
        }
        return null;
    }

    public static String handlePath(String path) {
        return path.replace("\\", "/");
    }

    public static String handlePackageName(String packageName) {
        String packageFullName;
        if (!packageName.contains(getMetadataPackageExtension())) {
            packageFullName = packageName + getMetadataPackageExtension();
        } else {
            packageFullName = packageName;
        }

        return packageFullName;
    }

    public static ObjectMapper getMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE);
        mapper.configure(JsonGenerator.Feature.IGNORE_UNKNOWN, true);
        mapper.configure(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, true);
        mapper.configure(JsonParser.Feature.ALLOW_MISSING_VALUES, true);
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);//大小写脱敏 默认为false  需要改为tru
        mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
        return mapper;
    }

    public static List<String> getMetadataPostfixTypes() {
        if (metadataPostfixTypes != null && metadataPostfixTypes.size() > 0) {
            return metadataPostfixTypes;
        }
        LOCK.lock();
        try {
            if (metadataPostfixTypes != null && metadataPostfixTypes.size() > 0) {
                return metadataPostfixTypes;
            }
            metadataPostfixTypes = new ArrayList<>();
            MetadataTypeConfigLoader loader = new MetadataTypeConfigLoader();
            List<MetadataType> typeList = loader.loadMetadataConfigurations();
            typeList.forEach(type ->
            {
                metadataPostfixTypes.add(type.getPostfix());
            });
            return metadataPostfixTypes;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            LOCK.unlock();
        }

        return null;
    }

    /**
     * 将源文件/文件夹生成指定格式的压缩文件,格式zip
     *
     * @param resourcesPath 源文件/文件夹
     * @param targetPath    目的压缩文件保存路径
     * @param targetName    目的压缩文件名
     */
    public static void compress(String resourcesPath, String targetPath, String targetName) {
        //源文件
        File resourcesFile = new File(resourcesPath);
        //目的
        File targetFile = new File(targetPath);
        //如果目的路径不存在，则新建
        if (!targetFile.exists()) {
            targetFile.mkdirs();
        }
        //目的压缩文件名
        targetName = targetName + ".mdpkg";
        try {
            FileOutputStream outputStream = new FileOutputStream(FileServiceImp.combinePath(targetPath, targetName));
            ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(outputStream));

            createCompressedFile(out, resourcesFile, "");

            out.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 生成压缩文件。如果是文件夹，则使用递归，进行文件遍历、压缩 如果是文件，直接压缩
     *
     * @param out  输出流
     * @param file 目标文件
     * @param dir  文件路径
     */
    public static void createCompressedFile(ZipOutputStream out, File file, String dir) {
        //如果当前的是文件夹，则进行进一步处理
        if (file.isDirectory()) {
            //得到文件列表信息
            File[] files = file.listFiles();
            try {
                //将文件夹添加到下一级打包目录
                out.putNextEntry(new ZipEntry(dir + "/"));
            } catch (Exception e) {
                throw new RuntimeException(e);
            }

            dir = dir.length() == 0 ? "" : dir + "/";

            //循环将文件夹中的文件打包
            for (int i = 0; i < files.length; i++) {
                createCompressedFile(out, files[i], dir + files[i].getName());         //递归处理
            }
        } else {   //当前的是文件，打包处理
            try {
                //文件输入流
                FileInputStream fis = new FileInputStream(file);

                out.putNextEntry(new ZipEntry(dir));
                //进行写操作
                int j = 0;
                byte[] buffer = new byte[1024];
                while ((j = fis.read(buffer)) > 0) {
                    out.write(buffer, 0, j);
                }
                //关闭输入流
                fis.close();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    public static void writeValue(String mdPath, MetadataProject mdProj) {
        try (FileOutputStream fileOutputStream = new FileOutputStream(mdPath)) {
            ObjectMapper objectMapper = getMapper();
            objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
            objectMapper.writeValue(fileOutputStream, mdProj);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static boolean nameValidating(String name) {
        if (StringUtils.isEmpty(name)) {
            return false;
        } else if (name.trim().length() > 255) {
            return false;
        } else {
            return StringUtils.indexOfAny(name.trim(), getInValidCharacter()) == -1;
        }
    }

    public static String[] getInValidCharacter() {
        return new String[] {"\\", "/", ":", "*", "?", "\"", "<", ">", "|", "&", "@", "\"", "‘", "’", "“", "”", "%", "；", ";"};
    }

    public static boolean isNullOrEmpty(String str) {
        return str == null || str.isEmpty();
    }

    public static boolean isNullOrEmpty(List list) {
        return list == null || list.size() == 0;
    }

    public static void checkNPE(Object obj, String msg) {
        if (obj == null) {
            throw new RuntimeException(msg);
        }
    }

    public static void checkEmpty(String str, String msg) {
        if (isNullOrEmpty(str)) {
            throw new RuntimeException(msg);
        }
    }

    public static String getMetadataPath() {
        return metadataPath;
    }

    public static void setMetadataPath(String metadataPath) {
        Utils.metadataPath = metadataPath;
    }
}
